package com.ikingtech.platform.service.system.dept.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ikingtech.framework.sdk.component.api.CompDepartmentApi;
import com.ikingtech.framework.sdk.component.model.ComponentDepartment;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.department.model.DeptBasicDTO;
import com.ikingtech.framework.sdk.department.model.DeptDTO;
import com.ikingtech.framework.sdk.enums.common.ElementTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.system.dept.entity.DepartmentDO;
import com.ikingtech.platform.service.system.dept.exception.DeptExceptionInfo;
import com.ikingtech.platform.service.system.dept.service.repository.DeptRepository;
import com.ikingtech.platform.service.system.dept.service.repository.ModelConverter;
import lombok.RequiredArgsConstructor;

import java.util.*;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
public abstract class AbstractCompDepartmentService implements CompDepartmentApi {

    private final DeptRepository repo;

    private final ModelConverter converter;

    @Override
    public List<ComponentDepartment> listByName(String name, Boolean dataScopeOnly) {
        List<DeptDTO> departments = this.converter.modelConvert(
                this.repo.list(
                        Wrappers.<DepartmentDO>lambdaQuery()
                                .like(DepartmentDO::getName, name)
                                .eq(DepartmentDO::getTenantCode, Me.tenantCode())
                                .orderByAsc(DepartmentDO::getSortOrder)
                ),
                Me.dataScope(),
                dataScopeOnly
        );
        return this.convert(departments, this.extractDepartmentFullName(Tools.Coll.convertMap(departments, DeptDTO::getId, DeptDTO::getFullPath)));
    }

    @Override
    public List<ComponentDepartment> listByParentId(String parentId, Boolean dataScopeOnly) {
        List<DeptDTO> departments = this.converter.modelConvert(
                this.repo.list(
                        Wrappers.<DepartmentDO>lambdaQuery()
                                .eq(DepartmentDO::getParentId, parentId)
                                .orderByAsc(DepartmentDO::getSortOrder)
                ),
                Me.dataScope(),
                dataScopeOnly
        );
        return this.convert(departments);
    }

    @Override
    public ComponentDepartment load(String parentId) {
        DepartmentDO entity = this.repo.getById(parentId);
        return this.convert(entity);
    }

    @Override
    public ComponentDepartment getRootDepartment() {
        DepartmentDO entity = this.repo.getOne(Wrappers.<DepartmentDO>lambdaQuery()
                .eq(Tools.Str.isNotBlank(Me.tenantCode()), DepartmentDO::getTenantCode, Me.tenantCode())
                .and(Tools.Str.isBlank(Me.tenantCode()), wrapper -> wrapper.isNull(DepartmentDO::getTenantCode).or().eq(DepartmentDO::getTenantCode, Tools.Str.EMPTY))
                .and(wrapper -> wrapper.isNull(DepartmentDO::getParentId).or().eq(DepartmentDO::getParentId, Tools.Str.EMPTY)));
        return this.convert(entity);
    }

    private ComponentDepartment convert(DepartmentDO entity) {
        if (null == entity) {
            throw new FrameworkException(DeptExceptionInfo.DEPT_NOT_FOUND);
        }
        ComponentDepartment result = new ComponentDepartment();
        result.setElementType(ElementTypeEnum.DEPT);
        result.setElementId(entity.getId());
        result.setElementName(entity.getName());
        return result;
    }

    private List<ComponentDepartment> convert(List<DeptDTO> departments) {
        return this.convert(departments, new HashMap<>());
    }

    private List<ComponentDepartment> convert(List<DeptDTO> departments, Map<String, String> departmentFullNameMap) {
        return Tools.Coll.convertList(departments, department -> {
            ComponentDepartment compDept = new ComponentDepartment();
            compDept.setElementId(department.getId());
            compDept.setElementName(department.getName());
            compDept.setElementType(ElementTypeEnum.DEPT);
            compDept.setManagerId(department.getManagerId());
            if (null != department.getManager()) {
                compDept.setManagerName(department.getManager().getUserName());
            }
            compDept.setUserCount(department.getUserCount());
            compDept.setFullPath(department.getFullPath());
            compDept.setDeptType(department.getType());
            if (null != compDept.getDeptType()) {
                compDept.setDeptTypeName(compDept.getDeptType().description);
            }
            compDept.setFullName(departmentFullNameMap.getOrDefault(department.getId(), Tools.Str.EMPTY));
            return compDept;
        });
    }

    @Override
    public Map<String, String> extractDepartmentFullName(Map<String, String> deptFullPathMap) {
        List<String> ids = Tools.Coll.flatMap(new ArrayList<>(deptFullPathMap.values()), fullPath -> Tools.Str.split(fullPath, "@"), Collection::stream);
        if (Tools.Coll.isBlank(ids)) {
            return new HashMap<>();
        }
        Map<String, String> departmentNameMap = Tools.Coll.convertMap(this.converter.modelInfoConvert(this.repo.listByIds(ids)), DeptBasicDTO::getId, DeptBasicDTO::getName);

        Map<String, String> result = new HashMap<>(deptFullPathMap.size());
        deptFullPathMap.forEach((deptId, deptFullPath) -> result.put(deptId, Tools.Coll.join(Tools.Coll.convertList(Tools.Str.split(deptFullPath, "@"), departmentNameMap::get), "-")));
        return result;
    }
}
